package visualization;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;

import javax.media.j3d.LineAttributes;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;

import export.NeuronToMatlabExport;

//import app.netmorphmodelcreator.tabs.LayerConfiguration;
import java.awt.BorderLayout;

import neuron.Layers;
import neuron.Network;
import neuron.Neuron;
import neuron.file.NetmorphLoader;
import neuron.file.NeuroLucidaLoader;
import neuron.geometry.CoordSet;
import neuron.geometry.Transform;
import neuron.geometry.Vector3d;

public class JNeuroView extends J3DView implements ActionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3165387513535865167L;

	// File info
	private File openFile;
	private double[] planeLocations;
	private Neuron openNeuron;
	private Network openNetwork;
	
	 

	FileFilter matFilter = new FileFilter() {
		public String getDescription() { return "Matlab files (*.MAT)"; }
		public boolean accept(File f) { return f.isDirectory() || f.getName().toUpperCase().endsWith(".MAT"); } 
	};
	  
	private void matlabExport()
	{
		// check that something is open
		if (openFile == null || openNeuron == null) {
			JOptionPane.showMessageDialog(this, "Open file first!", "Nothing to export", JOptionPane.WARNING_MESSAGE);
			return;
		}
		
		// init save dialog
		JFileChooser jfc = new JFileChooser(System.getProperty("user.home"));
		jfc.setFileFilter(matFilter);
		String fileName = "neuro_export.mat";
		if (openFile != null) {
			// suggest file with same name as neuron, but with .mat ending
			int lastDotIdx = openFile.getName().lastIndexOf('.'); 
			fileName = openFile.getName() + ".mat";
			if (lastDotIdx != -1) fileName = openFile.getName().substring(0, lastDotIdx) + ".mat";
		}

		// show dialog
		jfc.setSelectedFile(new File(System.getProperty("user.home"), fileName));
		int r = jfc.showSaveDialog(this);
		
		// if save pressed, save to file
		if (r == JFileChooser.APPROVE_OPTION) {
			System.out.println("SAVE TO " + jfc.getSelectedFile());
			if (jfc.getSelectedFile() != null) {
				try {
					NeuronToMatlabExport mat = new NeuronToMatlabExport(jfc.getSelectedFile(), openNeuron, planeLocations);
					mat.export();
				} catch (IOException e1) {
					JOptionPane.showMessageDialog(this, "Error writing: " + e1.getMessage());
				}
			}
		}
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		String cmd = e.getActionCommand();
		 if (cmd.equalsIgnoreCase("EXPORT.MATLAB")) {
			 matlabExport();
		}
	}
	  
 
	
	/**
	 * 
	 * Create toolbar
	 */
	private void createToolbar()
	{ 
//		addCustomToolbarButton(new ImageIcon("icons/Save24.gif"), "Export to Matlab..", "EXPORT.MATLAB", this);
	}
	
	/**
	 * Create new NeuronView. Use openFile(File f) to view file.
	 * 
	 * @param title
	 */
	public JNeuroView() {
		super();
		createToolbar();		
	}
 

    /**
     * Open file for viewing. PlaneLocations is a list of (pia, l4/l5, wm) locations, can be null. 
     * @param f
     * @param planeLocations
     * @throws FileNotFoundException
     * @throws IOException
     * @throws ParseException
     */
	public void openFile(File f, double[] planeLocations) throws FileNotFoundException, IOException, ParseException
	{
		if (f == null) return;
		
//		File f = new File("data/patrik/070311_exp2_zA.ASC");
//		File f = new File("data/patrik/070311_exp4_zA.ASC");
//		File f = new File("data/patrik/070316_exp2_zA.ASC");
//		double[] planes = new double[] { 740, 5,  0, -700 }; // 0703011_exp2_zA 
//		double[] planes = new double[] { 635, 25, 0, -475 }; // 0703011_exp4_zA 
		//double[] planes = new double[] { 680, 76, 0, -902 }; // 0703016_exp2_zA
		
		clearScene();
		
		System.out.println("Loading..");
		Network net = null;
		
		if (f.getAbsolutePath().toUpperCase().endsWith(".ASC")) {
			net = NeuroLucidaLoader.load(f);
			if (planeLocations != null) {
				double pia = planeLocations[0], l4l5 = planeLocations[1], soma = planeLocations[2], wm = planeLocations[3];
				net.setLayers(new Layers(pia, l4l5, soma, wm));
			}
		}
		else if (f.getAbsolutePath().toUpperCase().endsWith(".NEURONS")) {
			net = NetmorphLoader.load(f);

			double somaZ = net.get(0).getSoma().getPoints().get(0).z;
			System.out.println("SOMA ZZ " + somaZ);
			// layers, TODO make dynamic
/*			addToScene(addPlane(0-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "PIA 0um", Color.black));
			addToScene(addPlane(LayerConfiguration.rIz-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "I", Color.black));
			addToScene(addPlane(LayerConfiguration.rIIz-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "II", Color.black));
			addToScene(addPlane(LayerConfiguration.rIIIz-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "III", Color.black));
			addToScene(addPlane(LayerConfiguration.rIVz-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "IV", Color.black));
			addToScene(addPlane(LayerConfiguration.rVz-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "V", Color.black));
			addToScene(addPlane(LayerConfiguration.rVIz-somaZ, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "VI", Color.black));
*/
		}
		

		// Mark layers, pia, wm
		if (planeLocations != null) {
			double pia = planeLocations[0], l4l5 = planeLocations[1], soma = planeLocations[2], wm = planeLocations[3];
	        addToScene(addPlane(pia, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "PIA " + (int)pia + " um", Color.black));
	        addToScene(addPlane(l4l5, Color.BLACK, 2f, LineAttributes.PATTERN_DASH, "L4/L5 " + (int)l4l5 + " um (from pia " + (int)(pia-l4l5) + "um)", Color.black));
	//        addToScene(addPlane(soma, Color.gray, 1f, LineAttributes.PATTERN_DASH));
	        addToScene(addPlane(wm, Color.BLACK, 4f, LineAttributes.PATTERN_SOLID, "WHITE MATTER " + (int)wm + " um (from pia " + (int)(pia-wm) + "um)", Color.black));
		}
		
		
        // Create coordinate grid
        // vertical
        for (int i = -1000; i <= 1000; i+=100) {
            addToScene(addVertPlane(i, Color.lightGray, 2f, LineAttributes.PATTERN_SOLID, ""+i, Color.gray));
        }
        // horizontal
        for (int i = -1000; i <= 1000; i+=100) {
            addToScene(addPlane(i, Color.lightGray, 2f, LineAttributes.PATTERN_SOLID, ""+i+"um", Color.gray));
        }

		openFile = f;
		this.planeLocations = planeLocations;
		
        
		// show neuron / network
		if (net.size() == 1) {
			Neuron n = net.get(0);
			System.out.println("Transforming..");
			Transform.translateToOrigo(n);
			Transform.rotateApicalToYAxis(n);
			Transform.rotateMaxVariation(n);
	
			System.out.println("Creating 3D view..");
	//		J3DFrame frame = new J3DFrame("J3D Test");
			addToScene(NeuronJ3D.neuronToGroup(n));
			openNeuron = n;
			openNetwork = null;
		} else {
			
			// collect coordinates
			openNeuron = null;
			openNetwork = net;
			net.zeroMean();
			
			int c = 0;
			for (Neuron n : net) {
				System.out.println("SOMA " + n.getSoma().center());
				//Transform.rotateByVector(n, var);
				Colormap cm = null;
				if (c%4 == 0) cm = new Colormap(Colormap.RED_BASE);
				if (c%4 == 1) cm = new Colormap(Colormap.GREEN_BASE);
				if (c%4 == 2) cm = new Colormap(Colormap.BLUE_BASE);
				if (c%4 == 3) cm = new Colormap(60/360f);
				
				addToScene(NeuronJ3D.neuronToGroup(n, cm));
				c++;
			}
		}
	}

	public Neuron getOpenNeuron() {
		return openNeuron;
	}
	 
	public Network getOpenNetwork() {
		return openNetwork;
	}
    
}
